package tech.yunjing.train.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.yunjing.train.common.Constants;
import tech.yunjing.train.dao.AccountDetailDao;
import tech.yunjing.train.dao.ReceiveRedPacketHashOperations;
import tech.yunjing.train.dao.ReceiveRedPacketRecordRepository;
import tech.yunjing.train.entity.*;
import tech.yunjing.train.service.AccountService;
import tech.yunjing.train.service.LoginService;
import tech.yunjing.train.service.ReceiveRedPacketService;
import tech.yunjing.train.service.RedPacketService;
import tech.yunjing.train.service.exception.*;
import tech.yunjing.train.util.Utility;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * 抢红包serviceImpl
 * Created by zlc on 2017/6/8.
 */
@Service
public class ReceiveRedPacketServiceImpl implements ReceiveRedPacketService {

    @Autowired
    private ReceiveRedPacketHashOperations<SmallRedPacket> smallRedPacketHashOperations;
    @Autowired
    private ReceiveRedPacketRecordRepository receiveRedPacketRecordRepository;
    @Autowired
    private AccountService accountService;
    @Autowired
    private LoginService<UserInfo> loginService;
    @Autowired
    private RedPacketService redPacketService;
    @Autowired
    private AccountDetailDao accountDetailDao;

    /**
     * 抢红包方法
     *
     * @param redPacketName 大红包的名称
     * @param sendAccount   账户名称
     * @return 用户抢到的红包金额
     */
    @Override
    public Double receiveMoney(String redPacketName, String sendAccount, String receiveAccount) {
        //判断用户是否登录
        UserInfo userInfo = loginService.getUserAccount(receiveAccount);
        if (userInfo == null) {
            throw new UserLoginException("请登录！");
        }
        //查询所有的小红包
        List<SmallRedPacket> list = this.findAll(redPacketName, sendAccount);
        //判断该用户是否抢过该红包
        for (SmallRedPacket smallRedPacket : list) {
            if (receiveAccount.equals(smallRedPacket.getUserAccount())) {
                throw new SmallRedPacketNumberException("已经抢过了！");
            }
        }
        //从小红包集合中取一个小红包
        for (SmallRedPacket smallRedPacket : list) {
            //判断小红包状态 0表示未被抢 1表示已被抢 2表示逻辑删除
            if (Constants.SMALL_RED_PACKET_NORMAL.equals(smallRedPacket.getStatus())) {
                //将小红包设置为已领取状态
                smallRedPacket.setStatus(Constants.SMALL_RED_PACKET_ALREADY);
                //设置小红包领取时间
                smallRedPacket.setGetDate(new Date());
                //设置小红包领取者账户
                smallRedPacket.setUserAccount(receiveAccount);
                //修改redis中小红包的领取状态
                smallRedPacketHashOperations.put(redPacketName + sendAccount, smallRedPacket.getSmallRedPacketId() + "", smallRedPacket);
                //创建红包记录
                ReceiveRedPacketRecord receiveRedPacketRecord = new ReceiveRedPacketRecord();
                //设置红包记录中的金额
                receiveRedPacketRecord.setReceiveMoney(smallRedPacket.getSmallRedPacketAmount());
                //设置红包记录中抢红包用户的账户
                receiveRedPacketRecord.setReceiveAccount(receiveAccount);
                //设置抢到的红包名称
                receiveRedPacketRecord.setRedPacketName(redPacketName);
                //设置红包记录中发红包用户的账户
                receiveRedPacketRecord.setSendAccount(sendAccount);
                //设置记录查询状态
                receiveRedPacketRecord.setFindState(Constants.FIND_STATE_NORMAL);
                //设置红包记录中的领取时间
                receiveRedPacketRecord.setReceiveDate(smallRedPacket.getGetDate());
                //设置该记录的创建时间
                receiveRedPacketRecord.setCreateDate(new Date());
                //设置记录逻辑删除状态
                receiveRedPacketRecord.setLogicDelete(Constants.DEL_LOGIC_NORMAL);
                //将红包记录保存至数据库中
                receiveRedPacketRecordRepository.save(receiveRedPacketRecord);
                //获取该用户的账户记录
                Account account = accountService.findByAccountName(receiveAccount);
                //将抢到的钱增加到用户的账户中
                Double money = account.getAccountBalance() + smallRedPacket.getSmallRedPacketAmount();
                //将数据库中数据更新
                accountService.updateBalanceByAccountName(money, receiveAccount);
                //返回用户抢到的金额
                return smallRedPacket.getSmallRedPacketAmount();
            }
        }
        //红包抢完后，将大红包逻辑删除
        int a = redPacketService.removePacket(redPacketName, sendAccount);
        if (1 != a) {
            throw new SmallRedPacketNumberException("红包删除失败！");
        }
        throw new SmallRedPacketNumberException("红包已经抢完了！");
    }

    /**
     * 根据用户账户和大红包名称查询所有的小红包
     *
     * @param redPacketName 大红包名称
     * @param userAccount   用户账户
     * @return 查询到的小红包集合
     */
    @Override
    public List<SmallRedPacket> findAll(String redPacketName, String userAccount) {
        //检查接收到的大红包名称
        if (redPacketName == null || redPacketName.trim().isEmpty()) {
            throw new RedPacketNameException("名字不能为空!");
        }
        //检查账户
        if (userAccount == null || userAccount.trim().isEmpty()) {
            throw new UserAccountException("账户名错误!");
        }
        //从redis上获取所有的小红包
        List<SmallRedPacket> list = smallRedPacketHashOperations.getAll(redPacketName + userAccount);
        //判断其中是否有红包
        if (list.isEmpty()) {
            throw new SmallRedPacketNotFountException("红包查询失败!");
        }
        //判断小红包是否被逻辑删除
        Iterator<SmallRedPacket> smallRedPacketIterator = list.iterator();
        while (smallRedPacketIterator.hasNext()) {
            SmallRedPacket smallRedPacket = smallRedPacketIterator.next();
            //若被删除则从集合中移除
            if (Constants.SMALL_RED_PACKET_DELETE.equals(smallRedPacket.getStatus())) {
                smallRedPacketIterator.remove();
            }
        }
        return list;
    }

    /**
     * 根据用户账户和大红包名称逻辑删除小红包
     *
     * @param redPacketName 大红包名称
     * @param userAccount   用户账户
     * @return true表示成功
     */
    @Override
    public int removeSmallRedPacket(String redPacketName, String userAccount) {
        //检查账户
        if (userAccount == null || userAccount.trim().isEmpty()) {
            throw new UserAccountException("账户名错误!");
        }
        //判断用户是否登录
        UserInfo userInfo = loginService.getUserAccount(userAccount);
        if (userInfo == null) {
            throw new UserLoginException("请登录！");
        }
        //检查接收到的大红包名称
        if (redPacketName == null || redPacketName.trim().isEmpty()) {
            throw new RedPacketNameException("大红包名字错误!");
        }
        //获取小红包对象
        List<SmallRedPacket> list = this.findAll(redPacketName, userAccount);
        //判断其中是否有红包
        if (list.isEmpty()) {
            return 0;
        }
        //判断小红包是否被逻辑删除或已经抢过
        Iterator<SmallRedPacket> smallRedPacketIterator = list.iterator();
        while (smallRedPacketIterator.hasNext()) {
            SmallRedPacket smallRedPacket = smallRedPacketIterator.next();
            //若被删除或抢过则从集合中移除
            if (Constants.SMALL_RED_PACKET_DELETE.equals(smallRedPacket.getStatus()) ||
                    Constants.SMALL_RED_PACKET_ALREADY.equals(smallRedPacket.getStatus())) {
                smallRedPacketIterator.remove();
            }
        }
        //获取需要逻辑删除的小红包的钱数总额
        Double money = Utility.getTotal(list);
        //逻辑删除小红包
        for (SmallRedPacket smallRedPacket : list) {
            //将小红包状态设置为删除状态
            smallRedPacket.setStatus(Constants.SMALL_RED_PACKET_DELETE);
            //将逻辑删除的小红包存入redis中
            smallRedPacketHashOperations.put(redPacketName + userAccount, smallRedPacket.getSmallRedPacketId() + "", smallRedPacket);
        }
        //获取该用户的账户记录
        Account account = accountService.findByAccountName(userAccount);
        if (account == null) {
            throw new SmallRedPacketNumberException("账户不存在！");
        }
        //将逻辑删除的小红包的钱数总额加到用户的账户中
        int a = accountService.updateBalanceByAccountName(money+account.getAccountBalance(), userAccount);
        if (1 != a) {
            throw new SmallRedPacketNumberException("保存失败！");
        }
        //创建账户明细记录
        AccountDetail accountDetail = new AccountDetail();
        //设置明细记录的账户
        accountDetail.setAccountName(userAccount);
        //设置明细发生时间
        accountDetail.setHappendTime(new Date());
        //设置明细金额
        accountDetail.setHappendMoney(money);
        //将明细记录保存至数据库中
        a = accountDetailDao.addAccountDetail(accountDetail);
        if (1 != a) {
            throw new SmallRedPacketNumberException("保存失败！");
        }
        //将大红包逻辑删除
        a = redPacketService.removePacket(redPacketName, userAccount);
        if (1 != a) {
            throw new SmallRedPacketNumberException("红包删除失败！");
        }
        return list.size();
    }
}
